package com.jzo2o.customer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.customer.dto.response.AddressBookResDTO;
import com.jzo2o.api.publics.MapApi;
import com.jzo2o.api.publics.dto.response.LocationResDTO;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.model.Result;
import com.jzo2o.common.utils.*;
import com.jzo2o.customer.mapper.AddressBookMapper;
import com.jzo2o.customer.model.domain.AddressBook;
import com.jzo2o.customer.model.dto.request.AddressBookPageQueryReqDTO;
import com.jzo2o.customer.model.dto.request.AddressBookUpsertReqDTO;
import com.jzo2o.customer.service.IAddressBookService;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 地址薄 服务实现类
 * </p>
 *
 * @author itcast
 * @since 2023-07-06
 */
@Service
public class AddressBookServiceImpl extends ServiceImpl<AddressBookMapper, AddressBook> implements IAddressBookService {

    @Override
    public List<AddressBookResDTO> getByUserIdAndCity(Long userId, String city) {

        List<AddressBook> addressBooks = lambdaQuery()
                .eq(AddressBook::getUserId, userId)
                .eq(AddressBook::getCity, city)
                .list();
        if (CollUtils.isEmpty(addressBooks)) {
            return new ArrayList<>();
        }
        return BeanUtils.copyToList(addressBooks, AddressBookResDTO.class);
    }

    @Override
    public Result add(AddressBookUpsertReqDTO addressBookUpsertReqDTO) {
        //如果不是默认地址，则判断数据库中是否有默认地址，没有则这个地址必须设置成默认地址然后保存
        AddressBook addressBook = BeanUtils.toBean(addressBookUpsertReqDTO, AddressBook.class);
        addressBook.setUserId(UserContext.currentUserId());
        if (addressBookUpsertReqDTO.getIsDefault() == 0) {
            List<AddressBook> list = getAddressBooksByUserId();
            list = list.stream().filter(addr -> addr.getIsDefault() == 1).collect(Collectors.toList());
            if (CollUtils.isEmpty(list)) {
                addressBook.setIsDefault(1);
            }
            boolean save = save(addressBook);
            return save ? Result.ok() : Result.error("添加失败");
        }
        //如果是默认地址，则判断是否已经有地址
        List<AddressBook> list = getAddressBooksByUserId();
        List<AddressBookResDTO> addressBookResDTOS = BeanUtils.copyToList(list, AddressBookResDTO.class);
        //如果没有地址，则直接保存
        if (CollUtils.isEmpty(addressBookResDTOS)) {
            boolean save = save(addressBook);
            return save ? Result.ok() : Result.error("添加失败");
        }
        //如果有地址，则判断是否已经有默认地址
        addressBookResDTOS = addressBookResDTOS.stream().filter(addressBookResDTO -> addressBookResDTO.getIsDefault() == 1).collect(Collectors.toList());
        if (CollUtils.isEmpty(addressBookResDTOS)) {
            //如果没有默认地址，则直接保存
            boolean save = save(addressBook);
            return save ? Result.ok() : Result.error("添加失败");
        }
        //如果有默认地址，则更新默认地址为0
        addressBookResDTOS.forEach(addressBookResDTO -> {
            addressBookResDTO.setIsDefault(0);
            updateById(BeanUtils.toBean(addressBookResDTO, AddressBook.class));
        });
        List<AddressBook> addressBooks = addressBookResDTOS.stream().map(address -> BeanUtils.toBean(address, AddressBook.class)).collect(Collectors.toList());
        //保存新的默认地址
        addressBooks.add(addressBook);
        boolean b = this.saveOrUpdateBatch(addressBooks);
        return b ? Result.ok() : Result.error("添加失败");
    }

    @Override
    public PageResult<AddressBookResDTO> pageQuery(AddressBookPageQueryReqDTO addressBookPageQueryReqDTO) {
        Page<AddressBookResDTO> page = new Page<>(addressBookPageQueryReqDTO.getPageNo(), addressBookPageQueryReqDTO.getPageSize());
        String orderBy1 = addressBookPageQueryReqDTO.getOrderBy1();
        String orderBy2 = addressBookPageQueryReqDTO.getOrderBy2();
        //驼峰转下划线
        if (StringUtils.isNotBlank(orderBy1)) {
            addressBookPageQueryReqDTO.setOrderBy1(StringUtils.toUnderlineCase(orderBy1));
        }
        if (StringUtils.isNotBlank(orderBy2)) {
            addressBookPageQueryReqDTO.setOrderBy2(StringUtils.toUnderlineCase(orderBy2));
        }
        baseMapper.pageQuery(page, UserContext.currentUserId(), addressBookPageQueryReqDTO);

        PageResult<AddressBookResDTO> pageResult = PageUtils.toPage(page, AddressBookResDTO.class);
        return pageResult;
    }

    @Override
    public AddressBookResDTO getAddressBookById(Long id) {
        AddressBook addressBook = this.getById(id);
        if (ObjectUtils.isNull(addressBook)) {
            throw new BadRequestException("地址不存在");
        }
        return BeanUtils.toBean(addressBook, AddressBookResDTO.class);
    }

    @Override
    public Result updateAddressBookById(Long id, AddressBookUpsertReqDTO addressBookUpsertReqDTO) {
        AddressBook addressBook = this.getById(id);
        List<AddressBook> list = getAddressBooksByUserId();
        if (ObjectUtils.isNull(addressBook)) {
            throw new BadRequestException("地址不存在");
        }
        //如果只有一个地址，则判断是否是当前地址，一般来说，如果这个用户数据库只有一个地址，这个if都是成立的
        //但就怕他用其它手段拿到的id不是当前数据库的id，所以这里判断一下
        if (list.size() == 1) {
            AddressBook addr = list.get(0);
            if (ObjectUtils.equal(addr, addressBook)) {
                //获取经纬度，经纬度不是必传的
                BeanCopyTo(addressBookUpsertReqDTO, addressBook);
                //只有一个地址时，则强制默认地址
                addressBook.setIsDefault(1);
                boolean b = updateById(addressBook);
                return b ? Result.ok() : Result.error("更新失败");
            } else {
                throw new BadRequestException("地址错误");
            }
        }
        //如果数据库不止一个地址，并且形参这个地址是默认地址,就把数据库中默认地址改成非默认
        if (addressBookUpsertReqDTO.getIsDefault() == 1) {
            //如果是默认地址，则判断是否已经有默认地址
            list = list.stream().filter(addr -> addr.getIsDefault() == 1).collect(Collectors.toList());
            //如果数据库中没有默认地址，则直接保存当前地址
            if (CollUtils.isEmpty(list)) {
                BeanCopyTo(addressBookUpsertReqDTO, addressBook);
                boolean b = updateById(addressBook);
                return b ? Result.ok() : Result.error("更新失败");
            }
            //如果数据库中有默认地址，则判断是否是当前地址，如果是就直接保存当前地址
            if (ObjectUtils.equal(list.get(0), addressBook)) {
                BeanCopyTo(addressBookUpsertReqDTO, addressBook);
                boolean b = updateById(addressBook);
                return b ? Result.ok() : Result.error("更新失败");
            }
            //如果数据库中有默认地址，当前地址也要设置成默认地址,两个地址不一样，那就把数据库中的设置成非默认地址
            list.forEach(addr -> {
                addr.setIsDefault(0);
            });
            BeanCopyTo(addressBookUpsertReqDTO, addressBook);
            list.add(addressBook);
            boolean b = this.saveOrUpdateBatch(list);
            return b ? Result.ok() : Result.error("更新失败");
        }
        //如果当前设置地址为非默认，那判断从数据库获取的地址是不是默认地址，如果是默认地址，那你不能改成非默认，因为必须要有一个默认地址
        if (addressBookUpsertReqDTO.getIsDefault() == 0) {
            if (addressBook.getIsDefault() == 1) {
                throw new BadRequestException("当前地址为默认地址，不能设置为非默认地址");
            }
            BeanCopyTo(addressBookUpsertReqDTO, addressBook);
            boolean b = updateById(addressBook);
            return b ? Result.ok() : Result.error("更新失败");
        }
        throw new BadRequestException("传递参数不正确");
    }

    @Override
    public Result setDefault(Long id, Integer flag) {
        AddressBook addressBook = getDefaultAddress();
        //判断数据库中是否有默认地址
        if (ObjectUtils.isNotNull(addressBook)) {
            //如果数据库中有默认地址，判断当前地址是否要修改成默认地址
            if (flag == 1) {
                //如果当前地址要修改成默认地址，且当前地址是数据库中的默认地址，那不必更新，减少一次数据库IO
                if (addressBook.getId().equals(id)) {
//                    addressBook.setIsDefault(flag);
//                    boolean b = updateById(addressBook);
                    return Result.ok();
                }
                //如果当前地址要修改成默认地址，但它不是数据库中的默认地址，那就把数据库中的设置成非默认地址，把当前地址设置成默认地址
                addressBook.setIsDefault(0);
                updateById(addressBook);
                boolean b = updateById(new AddressBook().setId(id).setIsDefault(flag));
                return b ? Result.ok() : Result.error("更新失败");
            }
        }
        //如果数据库中没有默认地址，那直接修改就好了
        boolean b = updateById(new AddressBook().setId(id).setIsDefault(flag));
        return b ? Result.ok() : Result.error("更新失败");
    }

    @Override
    public AddressBook getDefaultAddress() {
        LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AddressBook::getUserId, UserContext.currentUserId())
                .eq(AddressBook::getIsDeleted, 0)
                .eq(AddressBook::getIsDefault, 1);
        return this.getOne(queryWrapper);
    }

    private void BeanCopyTo(AddressBookUpsertReqDTO addressBookUpsertReqDTO, AddressBook addressBook) {
        if (StringUtils.isNotBlank(addressBookUpsertReqDTO.getLocation())) {
            String location = addressBookUpsertReqDTO.getLocation();
            String[] split = location.split(",");
            addressBook.setLon(Double.parseDouble(split[0]));
            addressBook.setLat(Double.parseDouble(split[1]));
        }
        addressBook.setName(addressBookUpsertReqDTO.getName());
        addressBook.setPhone(addressBookUpsertReqDTO.getPhone());
        addressBook.setProvince(addressBookUpsertReqDTO.getProvince());
        addressBook.setCity(addressBookUpsertReqDTO.getCity());
        addressBook.setCounty(addressBookUpsertReqDTO.getCounty());
        addressBook.setAddress(addressBookUpsertReqDTO.getAddress());
        addressBook.setIsDefault(addressBookUpsertReqDTO.getIsDefault());
    }

    /**
     * 根据用户id获取地址
     *
     * @return 地址列表
     */
    private List<AddressBook> getAddressBooksByUserId() {
        LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AddressBook::getUserId, UserContext.currentUserId());
        return list(queryWrapper);
    }

}
